package com.quad.innovators.salesease.service.impl.warehouse;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quad.innovators.salesease.common.result.PageResultBean;
import com.quad.innovators.salesease.common.utils.SystemCodeUtils;
import com.quad.innovators.salesease.converter.VehicleBringGoodsConverter;
import com.quad.innovators.salesease.enums.ResultCode;
import com.quad.innovators.salesease.enums.ScanCodeTypeEnum;
import com.quad.innovators.salesease.enums.SystemCodeEnum;
import com.quad.innovators.salesease.enums.VehicleBringExamineEnum;
import com.quad.innovators.salesease.enums.VehicleBringScanTypeEnum;
import com.quad.innovators.salesease.exception.BusinessException;
import com.quad.innovators.salesease.mapper.warehouse.VehicleBringGoodsMapper;
import com.quad.innovators.salesease.model.entity.stock.ProductInfoIdentity;
import com.quad.innovators.salesease.model.entity.warehouse.VehicleBringGoods;
import com.quad.innovators.salesease.model.entity.warehouse.VehicleBringScanCode;
import com.quad.innovators.salesease.model.form.warehouse.VehicleBringGoodsForm;
import com.quad.innovators.salesease.model.form.warehouse.VehicleBringScanCodeForm;
import com.quad.innovators.salesease.model.query.warehouse.VehicleBringGoodsPageQuery;

import com.quad.innovators.salesease.model.vo.warehouse.VehicleBringGoodsVO;

import com.quad.innovators.salesease.service.stock.ProductInfoIdentityService;
import com.quad.innovators.salesease.service.warehouse.SaleReturnOrderService;
import com.quad.innovators.salesease.service.warehouse.VehicleBringGoodsService;
import com.quad.innovators.salesease.service.warehouse.VehicleBringScanCodeService;


import org.apache.commons.compress.utils.Lists;
import org.apache.commons.compress.utils.Sets;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;

/**
 * @author : shanshan.li
 * @createTime : 2025/4/3 09:41
 * @Version : 1.0 
 */
@Service
@RequiredArgsConstructor
public class VehicleBringGoodsServiceImpl extends ServiceImpl<VehicleBringGoodsMapper, VehicleBringGoods> implements VehicleBringGoodsService {

    private final VehicleBringGoodsConverter vehicleBringGoodsConverter;

    private final VehicleBringScanCodeService vehicleBringScanCodeService;

    private final SaleReturnOrderService saleReturnOrderService;

    private final ProductInfoIdentityService productInfoIdentityService;

    @Override
    public PageResultBean<VehicleBringGoodsVO> listPage(VehicleBringGoodsPageQuery queryParams) {
        Page<VehicleBringGoodsVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        Page<VehicleBringGoodsVO> warehouseVOPage = this.baseMapper.listPage(page, queryParams);
        return vehicleBringGoodsConverter.toPageVo(warehouseVOPage);
    }

    @Override
    public VehicleBringGoodsForm getFormData(String code) {
        VehicleBringGoods vehicleBringGoods = this.baseMapper.selectOne(new QueryWrapper<VehicleBringGoods>().lambda().eq(VehicleBringGoods::getCode, code));
        if (ObjectUtils.isEmpty(vehicleBringGoods)) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        VehicleBringGoodsForm vehicleBringGoodsConverterForm = vehicleBringGoodsConverter.toForm(vehicleBringGoods);
        vehicleBringGoodsConverterForm.setSaleReturnCodeList(saleReturnOrderService.getSaleReturnCodeList(code));
        vehicleBringGoodsConverterForm.setVehicleBringScanCodeFormList(vehicleBringScanCodeService.getListByVehicleCode(code));
        return vehicleBringGoodsConverterForm;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(VehicleBringGoodsForm form) {
        VehicleBringGoods vehicleBringGoods = vehicleBringGoodsConverter.toEntity(form);
        vehicleBringGoods.setExamineResultType(VehicleBringExamineEnum.UNTESTED.getCode());
        vehicleBringGoods.setCode(SystemCodeUtils.getCode(SystemCodeEnum.SALE_RETURN_ORDER));
        vehicleBringGoods.setCode(SystemCodeUtils.getCode(SystemCodeEnum.VEHICLE_BRING));
        return this.baseMapper.insert(vehicleBringGoods) > 0
                && saleReturnOrderService.bindSaleReturnOrder(vehicleBringGoods.getCode(), form.getSaleReturnCodeList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(String code, VehicleBringGoodsForm form) {
        VehicleBringGoods vehicleBringGoods = this.baseMapper.selectOne(new QueryWrapper<VehicleBringGoods>().lambda().eq(VehicleBringGoods::getCode, code));
        if (ObjectUtils.isEmpty(vehicleBringGoods)) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        VehicleBringGoods entity = vehicleBringGoodsConverter.toEntity(form);
        entity.setExamineResultType(VehicleBringExamineEnum.UNTESTED.getCode());
        entity.setManyNumber(0);
        entity.setLackNumber(0);
        entity.setId(vehicleBringGoods.getId());
        return this.updateById(entity)
                && saleReturnOrderService.updateBindSaleReturnOrder(code, form.getSaleReturnCodeList())
                && vehicleBringScanCodeService.remove(new QueryWrapper<VehicleBringScanCode>().lambda().eq(VehicleBringScanCode::getVehicleBringGoodsCode, code)
                .and(model -> model.eq(VehicleBringScanCode::getScanType, VehicleBringScanTypeEnum.MANY.getCode()).or().eq(VehicleBringScanCode::getScanType, VehicleBringScanTypeEnum.LACK.getCode())));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean examineResult(String code) {
        VehicleBringGoods vehicleBringGoods = this.baseMapper.selectOne(new QueryWrapper<VehicleBringGoods>().lambda().eq(VehicleBringGoods::getCode, code));
        if (ObjectUtils.isEmpty(vehicleBringGoods)) {
            throw BusinessException.resultCode(ResultCode.NOT_FOUND);
        }
        // 获取订单的销售扫码和退货扫码
        List<String> saleOrderScanCodeList = saleReturnOrderService.getSaleScanCodeByVehicleCode(code);
        List<String> returnOrderScanCodeList = saleReturnOrderService.getReturnScanCodeByVehicleCode(code);

        // 获取车辆扫描
        List<VehicleBringScanCodeForm> listByVehicleCode = vehicleBringScanCodeService.getListByVehicleCode(code);

        Set<String> scanCode = Sets.newHashSet();
        scanCode.addAll(saleOrderScanCodeList);
        scanCode.addAll(returnOrderScanCodeList);
        scanCode.addAll(listByVehicleCode.stream().map(VehicleBringScanCodeForm::getScanCode).collect(Collectors.toSet()));

        // 通过包装码查询全部信息
        List<ProductInfoIdentity> productInfoIdentityList = productInfoIdentityService.list(new QueryWrapper<ProductInfoIdentity>().lambda().in(ProductInfoIdentity::getPackingCode, scanCode));

        // 根据身份码找到对应信息
        Map<String, ProductInfoIdentity> getIdentityByCodeMap = productInfoIdentityList.stream().collect(Collectors.toMap(ProductInfoIdentity::getIdentityCode, model -> model));

        // 根据包装码分组
        Map<String, List<String>> packingGetIdentityCode = productInfoIdentityList.stream().collect(Collectors.groupingBy(ProductInfoIdentity::getPackingCode, Collectors.mapping(ProductInfoIdentity::getIdentityCode, Collectors.toList())));

        // 包装码转换为身份码
        Set<String> saleOrderScanCodeSet = transforPackingToIdentity(new HashSet<>(saleOrderScanCodeList), packingGetIdentityCode);
        Set<String> returnOrderScanCodeSet = transforPackingToIdentity(new HashSet<>(returnOrderScanCodeList), packingGetIdentityCode);

        // 车辆去回货
        Set<String> vehicleShippingSet = transforPackingToIdentity(listByVehicleCode.stream().filter(model -> VehicleBringScanTypeEnum.SHIPPING.getCode().equals(model.getScanType())).map(VehicleBringScanCodeForm::getScanCode).collect(Collectors.toSet()), packingGetIdentityCode);
        Set<String> vehicleReturnSet = transforPackingToIdentity(listByVehicleCode.stream().filter(model -> VehicleBringScanTypeEnum.RETURN.getCode().equals(model.getScanType())).map(VehicleBringScanCodeForm::getScanCode).collect(Collectors.toSet()), packingGetIdentityCode);

        // 销售和退货都存在的情况下, 市场内部调换。去除。
        Set<String> saleReturnPublicSet = Sets.newHashSet();
        for (String s : saleOrderScanCodeSet) {
            if (returnOrderScanCodeSet.contains(s)) {
                saleReturnPublicSet.add(s);
            }
        }
        if (CollectionUtils.isNotEmpty(saleReturnPublicSet)) {
            saleOrderScanCodeSet = saleOrderScanCodeSet.stream().filter(model -> !saleReturnPublicSet.contains(model)).collect(Collectors.toSet());
            returnOrderScanCodeSet = returnOrderScanCodeSet.stream().filter(model -> !saleReturnPublicSet.contains(model)).collect(Collectors.toSet());
        }

        List<VehicleBringScanCode> manyVehicleBringScanCodeList = Lists.newArrayList();
        List<VehicleBringScanCode> lackVehicleBringScanCodeList = Lists.newArrayList();

        // 检查销售的货是否都存在车辆带货
        Set<String> vehicleSalePublicSet = Sets.newHashSet();
        for (String s : saleOrderScanCodeSet) {
            if (vehicleShippingSet.contains(s)) {
                vehicleSalePublicSet.add(s);
            } else {
                VehicleBringScanCode vehicleBringScanCode = new VehicleBringScanCode();
                vehicleBringScanCode.setCode(SystemCodeUtils.getCode(SystemCodeEnum.VEHICLE_BRING_SCAN_CODE));
                vehicleBringScanCode.setVehicleBringGoodsCode(code);
                vehicleBringScanCode.setProductName(getIdentityByCodeMap.get(s).getProductName());
                vehicleBringScanCode.setScanCode(s);
                vehicleBringScanCode.setScanType(VehicleBringScanTypeEnum.MANY.getCode());
                vehicleBringScanCode.setScanCodeType(ScanCodeTypeEnum.IDENTITY_CODE.getCode());
                manyVehicleBringScanCodeList.add(vehicleBringScanCode);
            }
        }

        // 去除销售出去的货
        vehicleShippingSet = vehicleShippingSet.stream().filter(model -> !vehicleSalePublicSet.contains(model)).collect(Collectors.toSet());

        // 加上退货
        vehicleShippingSet.addAll(returnOrderScanCodeSet);

        // 出去货和回来货对比
        for (String s : vehicleShippingSet) {
            if (!vehicleReturnSet.contains(s)) {
                VehicleBringScanCode vehicleBringScanCode = new VehicleBringScanCode();
                vehicleBringScanCode.setCode(SystemCodeUtils.getCode(SystemCodeEnum.VEHICLE_BRING_SCAN_CODE));
                vehicleBringScanCode.setVehicleBringGoodsCode(code);
                vehicleBringScanCode.setProductName(getIdentityByCodeMap.get(s).getProductName());
                vehicleBringScanCode.setScanCode(s);
                vehicleBringScanCode.setScanType(VehicleBringScanTypeEnum.LACK.getCode());
                vehicleBringScanCode.setScanCodeType(ScanCodeTypeEnum.IDENTITY_CODE.getCode());
                lackVehicleBringScanCodeList.add(vehicleBringScanCode);
            }
        }

        for (String s : vehicleReturnSet ){
            if (!vehicleShippingSet.contains(s)) {
                VehicleBringScanCode vehicleBringScanCode = new VehicleBringScanCode();
                vehicleBringScanCode.setCode(SystemCodeUtils.getCode(SystemCodeEnum.VEHICLE_BRING_SCAN_CODE));
                vehicleBringScanCode.setVehicleBringGoodsCode(code);
                vehicleBringScanCode.setProductName(getIdentityByCodeMap.get(s).getProductName());
                vehicleBringScanCode.setScanCode(s);
                vehicleBringScanCode.setScanType(VehicleBringScanTypeEnum.MANY.getCode());
                vehicleBringScanCode.setScanCodeType(ScanCodeTypeEnum.IDENTITY_CODE.getCode());
                manyVehicleBringScanCodeList.add(vehicleBringScanCode);
            }
        }
        vehicleBringGoods.setLackNumber(lackVehicleBringScanCodeList.size());
        vehicleBringGoods.setManyNumber(manyVehicleBringScanCodeList.size());
        if (CollectionUtils.isNotEmpty(lackVehicleBringScanCodeList) || CollectionUtils.isNotEmpty(manyVehicleBringScanCodeList)){
            vehicleBringGoods.setExamineResultType(VehicleBringExamineEnum.INCONSISTENCY.getCode());
        } else {
            vehicleBringGoods.setExamineResultType(VehicleBringExamineEnum.CONSISTENCY.getCode());
        }
        vehicleBringScanCodeService.remove(new QueryWrapper<VehicleBringScanCode>().lambda().eq(VehicleBringScanCode::getVehicleBringGoodsCode, code)
                .and(model -> model.eq(VehicleBringScanCode::getScanType, VehicleBringScanTypeEnum.MANY.getCode())
                        .or().eq(VehicleBringScanCode::getScanType, VehicleBringScanTypeEnum.LACK.getCode())));
        vehicleBringScanCodeService.saveBatch(manyVehicleBringScanCodeList);
        vehicleBringScanCodeService.saveBatch(lackVehicleBringScanCodeList);
        this.updateById(vehicleBringGoods);
        return true;
    }

    public Set<String> transforPackingToIdentity(Set<String> examineSet, Map<String, List<String>> transforMap) {
        Set<String> identitySet = Sets.newHashSet();
        for (String s : examineSet) {
            if (transforMap.containsKey(s)) {
                identitySet.addAll(transforMap.get(s));
            } else {
                identitySet.add(s);
            }
        }
        return identitySet;
    }
}













